package com.example.demo.algorithm.sort;

/**
 * @Description: 归并排序
 * 1.尽可能的一组数据拆分成两个元素相等的子组，并对每一个子组继续拆分，直到拆分后的每个子组的元素个数是 1为止。
 * 2.将相邻的两个子组进行合并成一个有序的大组;
 * 3.不断的重复步骤2，直到最终只有一个组为止。
 * @Author: xiatian
 * @CreateTime: 2021/9/10
 */
public class Merge {
    /**
     * 完成归并操作需要的辅助数组
     */
    private static Comparable[] assist;

    /**
     * 对数组内的元素进行排序
     *
     * @param a
     */
    public static void sort(Comparable[] a) {
        assist = new Comparable[a.length];
        int lo = 0;
        int hi = a.length - 1;
        sort(a, lo, hi);
    }

    /**
     * 对数组a中从索引lo到索引hi之间的元素进行排序
     *
     * @param a
     * @param lo
     * @param hi
     */
    public static void sort(Comparable[] a, int lo, int hi) {
        if (lo >= hi) {
            return;
        }
        int mid = lo + (hi - lo) / 2;  //3,1
        //递归分组排序
        sort(a, lo, mid);//0~3  0~1 00
        sort(a, mid + 1, hi);//4~7  6~7  77
        //再把两个组中的数据进行归并
        merge(a, lo, mid, hi);
        System.out.println("lo=" + lo + " mid = " + mid + "hi=" + hi);
    }

    /**
     * 从索引lo到索引mid为一个子组，从索引mid+1到索引hi为另一个子组，把数组a中的这两个子组的数据合并成一个有序的大组(从 索引lo到索引hi)
     *
     * @param a
     * @param lo
     * @param mid
     * @param hi
     */
    private static void merge(Comparable[] a, int lo, int mid, int hi) {
        //定义三个索引
        int p1 = lo;
        int p2 = mid + 1;
        int i = lo;
        while (p1 <= mid && p2 <= hi) {
            if (less(a[p1], a[p2])) {
                assist[i++] = a[p1++];
            } else {
                assist[i++] = a[p2++];
            }
        }
        //遍历，如果p1的指针没有走完，那么顺序移动p1指针，把对应的元素放到辅助数组的对应索引处
        while (p1 <= mid) {
            assist[i++] = a[p1++];
        }
        //遍历，如果p2的指针没有走完，那么顺序移动p2指针，把对应的元素放到辅助数组的对应索引处
        while (p2 <= hi) {
            assist[i++] = a[p2++];
        }
        //将辅助数组的数据复制到a中
        for (int index = 0; index <= hi; index++) {
            a[index] = assist[index];
        }
    }

    public static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    /**
     * 交换数组中，索引i和j的值
     *
     * @param a
     * @param i
     * @param j
     */
    public static void exch(Comparable[] a, int i, int j) {
        Comparable temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

}
